/**
 * Copyright (c) 2010
 * Bert Young. UESTC. 
 */

#ifndef BERT_MUTEX_H
#define BERT_MUTEX_H

#include <pthread.h>
#include "Noncopyable.h"

class Mutex : Noncopyable
{
	/**
	 * Posix mutex
	 */
	pthread_mutex_t mutex;
public:
	/**
	 * Constructor
	 */
	Mutex()
	{
		pthread_mutexattr_t attr;
		::pthread_mutexattr_init(&attr);
		::pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP);
		::pthread_mutex_init(&this->mutex, &attr);
	}
	/**
	 * Destructor
	 */
	~Mutex()
	{
		::pthread_mutex_destroy(&this->mutex);
	}
	/**
	 * lock
	 */
	void lock()
	{
		::pthread_mutex_lock(&this->mutex);
	}
	/**
	 * unlock
	 */
	void unlock()
	{
		::pthread_mutex_unlock(&this->mutex);
	}
};

class ScopeMutex
{
	/**
	 * Use mutex with RAII
	 */
	Mutex & mutex;
public:
	/**
	 * Constructor : lock
	 */
	ScopeMutex(Mutex & m) : mutex(m)
	{
		mutex.lock();
	}
	/**
	 * Destructor : unlock
	 */
	~ScopeMutex()
	{
		mutex.unlock();
	}
};

class RWLock : Noncopyable
{
	/**
	 * Posix rwlock
	 */
	pthread_rwlock_t rwlock;
public:
	/**
	 * Constructor
	 */
	RWLock()
	{
		::pthread_rwlock_init( &rwlock, NULL );
	}
	/**
	 * Destructor
	 */
	~RWLock()
	{
		::pthread_rwlock_destroy( &rwlock );
	}
	/**
	 * Read lock
	 */
	void rdlock()
	{
		::pthread_rwlock_rdlock( &rwlock );
	}
	/**
	 * Write lock
	 */
	void wrlock()
	{
		::pthread_rwlock_wrlock( &rwlock );
	}
	/**
	 * unlock
	 */
	void unlock()
	{
		::pthread_rwlock_unlock( &rwlock );
	}
};

class ScopeReadLock
{
	/**
	 * Use read lock with RAII
	 */
	RWLock & lock;
public:
	/**
	 * Constructor : read lock
	 */
	ScopeReadLock(RWLock & m) : lock(m)
	{
		lock.rdlock();
	}
	/**
	 * Destructor : unlock
	 */
	~ScopeReadLock()
	{
		lock.unlock();
	}
};

class ScopeWriteLock
{
	/**
	 * Use write lock with RAII
	 */
	RWLock & lock;
public:
	/**
	 * Constructor : write lock
	 */
	ScopeWriteLock(RWLock & m) : lock(m)
	{
		lock.wrlock();
	}
	/**
	 * Destructor : unlock
	 */
	~ScopeWriteLock()
	{
		lock.unlock();
	}
};

#endif

